"""
这段代码定义了一个 TaskWorker 类，该类继承自 QThread 类，并使用队列实现了任务的异步执行。
主程序中创建了一个 TaskWorker 实例，将任务添加到任务队列中，并使用定时器定期添加任务。
当任务完成时，TaskWorker 实例会发出信号，主程序中的槽函数会接收到这些信号并进行处理。

 代码具体步骤如下：
 1. 在主程序中定义一个 do_task 函数，该函数用于执行任务。
 2. 在主程序中定义两个槽函数 on_result 和 on_error，分别用于处理任务完成和任务出错的信号。
 3. 创建一个 TaskWorker 实例。
 4. 将 TaskWorker 实例的信号连接到槽函数。
 5. 将任务添加到任务队列中，并使用定时器定期添加任务。
 6. 运行主程序，等待任务执行完成。
"""

import sys
import threading
import time
from queue import Queue
from PyQt5.QtCore import QThread, pyqtSignal, pyqtSlot, QTimer


class TaskWorker(QThread):
    taskResult = pyqtSignal(object)
    taskError = pyqtSignal(Exception)
    taskFinished = pyqtSignal()

    def __init__(self, do_task, parent=None):
        super(TaskWorker, self).__init__(parent)
        self.do_task = do_task
        self.task_queue = Queue()
        self.is_running = True

    def run(self):
        while self.is_running:
            # 不断从队列中取出任务并执行，如果没有任务则阻塞
            task_arg = self.task_queue.get()
            if task_arg is None and not self.is_running:
                break
            try:
                result = self.do_task(task_arg)
                self.taskResult.emit(result)
            except Exception as e:
                self.taskError.emit(e)
        self.taskFinished.emit()

    def signal_connect(self, result_handler=None, finished_handler=None, error_handler=None):

        # Connect the worker's signal to the handler slot
        if result_handler is not None:
            self.taskResult.connect(result_handler)
        if finished_handler is not None:
            self.taskFinished.connect(finished_handler)
        if error_handler is not None:
            self.taskError.connect(error_handler)

        return

    def join_queue(self, task):
        if not self.is_running:
            return

        self.task_queue.put(task)

    def stop(self):
        self.is_running = False
        # Put a None task to the queue to stop the thread
        self.task_queue.put(None)


if __name__ == '__main__':
    from PyQt5.QtWidgets import QApplication


    def do_task(task):
        a, b = task
        rst = a / b
        # Simulate a time-consuming task
        time.sleep(1)  # Pause for 1 seconds
        return f"Task finished {a} / {b} = {rst}"


    @pyqtSlot(object)
    def on_result(result):
        # print(threading.currentThread())
        print("finish: ", result)


    @pyqtSlot(Exception)
    def on_error(e):
        # print(threading.currentThread())
        print("error: ", e)


    app = QApplication(sys.argv)

    print("main: ", threading.currentThread())

    task_worker = TaskWorker(do_task)
    task_worker.signal_connect(
        result_handler=on_result,
        finished_handler=lambda: print("finished"),
        error_handler=on_error,
    )
    task_worker.start()

    # Add tasks to the task manager
    task_worker.join_queue((3, 2))
    task_worker.join_queue((4, 2))
    task_worker.join_queue((5, 0))

    # Use a timer to add tasks periodically
    timer = QTimer()
    timer.timeout.connect(lambda: task_worker.join_queue((5, 2)))
    timer.start(3000)  # Add a task every 5 seconds

    # 执行一个5秒后的延时任务
    QTimer.singleShot(7000, lambda: task_worker.stop())

    sys.exit(app.exec_())
